fontchooserwidget: Refactor code so we actually optimize
authorBenjamin Otte <otte@redhat.com>
Wed, 22 Jul 2015 13:04:34 +0000 (15:04 +0200)
committerBenjamin Otte <otte@redhat.com>
Wed, 22 Jul 2015 14:01:21 +0000 (16:01 +0200)
Previously, we would pango_font_describe() every time the code ran and
we wouldn't ever hit the optimized quick exit.

The code now is a lot more complex because the
compute-actual-value-when-required-the-first-time approach is not
supported out of the box in GtkTreeModel (or GValue).

gtk/gtkfontchooserwidget.c
gtk/ui/gtkfontchooserwidget.ui

index 317aef79d3c09c2fecdfb05cf3fb09008fff8aca..a30f8af1445eb4511aeae56c61357d6eff073b2b 100644 (file)
@@ -145,9 +145,9 @@ static void     gtk_font_chooser_widget_set_font         (GtkFontChooserWidget *
                                                           const gchar          *fontname);
 
 static PangoFontDescription *gtk_font_chooser_widget_get_font_desc  (GtkFontChooserWidget *fontchooser);
-static void                  gtk_font_chooser_widget_merge_font_desc(GtkFontChooserWidget *fontchooser,
-                                                                     PangoFontDescription *font_desc,
-                                                                     GtkTreeIter          *iter);
+static void                  gtk_font_chooser_widget_merge_font_desc(GtkFontChooserWidget       *fontchooser,
+                                                                     const PangoFontDescription *font_desc,
+                                                                     GtkTreeIter                *iter);
 static void                  gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
                                                                      PangoFontDescription *font_desc);
 
@@ -179,6 +179,63 @@ G_DEFINE_TYPE_WITH_CODE (GtkFontChooserWidget, gtk_font_chooser_widget, GTK_TYPE
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FONT_CHOOSER,
                                                 gtk_font_chooser_widget_iface_init))
 
+typedef struct _GtkDelayedFontDescription GtkDelayedFontDescription;
+struct _GtkDelayedFontDescription {
+  PangoFontFace        *face;
+  PangoFontDescription *desc;
+  guint                 ref_count;
+};
+
+static GtkDelayedFontDescription *
+gtk_delayed_font_description_new (PangoFontFace *face)
+{
+  GtkDelayedFontDescription *result;
+  
+  result = g_slice_new0 (GtkDelayedFontDescription);
+
+  result->face = g_object_ref (face);
+  result->desc = NULL;
+  result->ref_count = 1;
+
+  return result;
+}
+
+static GtkDelayedFontDescription *
+gtk_delayed_font_description_ref (GtkDelayedFontDescription *desc)
+{
+  desc->ref_count++;
+
+  return desc;
+}
+
+static void
+gtk_delayed_font_description_unref (GtkDelayedFontDescription *desc)
+{
+  desc->ref_count--;
+
+  if (desc->ref_count > 0)
+    return;
+
+  g_object_unref (desc->face);
+  if (desc->desc)
+    pango_font_description_free (desc->desc);
+
+  g_slice_free (GtkDelayedFontDescription, desc);
+}
+
+static const PangoFontDescription *
+gtk_delayed_font_description_get (GtkDelayedFontDescription *desc)
+{
+  if (desc->desc == NULL)
+    desc->desc = pango_font_face_describe (desc->face);
+
+  return desc->desc;
+}
+
+#define GTK_TYPE_DELAYED_FONT_DESCRIPTION (gtk_delayed_font_description_get_type ())
+G_DEFINE_BOXED_TYPE (GtkDelayedFontDescription, gtk_delayed_font_description,
+                     gtk_delayed_font_description_ref,
+                     gtk_delayed_font_description_unref)
 static void
 gtk_font_chooser_widget_set_property (GObject         *object,
                                       guint            prop_id,
@@ -379,39 +436,13 @@ row_activated_cb (GtkTreeView       *view,
   g_free (fontname);
 }
 
-static PangoFontDescription *
-tree_model_get_font_description (GtkTreeModel *model,
-                                 GtkTreeIter  *iter)
-{
-  PangoFontDescription *desc, *face_desc;
-  PangoFontFace *face;
-
-  gtk_tree_model_get (model, iter,
-                      FONT_DESC_COLUMN, &desc,
-                      -1);
-  if (pango_font_description_get_set_fields (desc) != 0)
-    return desc;
-
-  gtk_tree_model_get (model, iter,
-                      FACE_COLUMN, &face,
-                      -1);
-  face_desc = pango_font_face_describe (face);
-  g_object_unref (face);
-  
-  pango_font_description_merge (desc, face_desc, TRUE);
-
-  pango_font_description_free (face_desc);
-
-  return desc;
-}
-
 static void
 cursor_changed_cb (GtkTreeView *treeview,
                    gpointer     user_data)
 {
   GtkFontChooserWidget *fontchooser = user_data;
   GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
-  PangoFontDescription *desc;
+  GtkDelayedFontDescription *desc;
   GtkTreeIter filter_iter, iter;
   GtkTreePath *path = NULL;
 
@@ -431,9 +462,15 @@ cursor_changed_cb (GtkTreeView *treeview,
   gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (priv->filter_model),
                                                     &iter,
                                                     &filter_iter);
-  desc = tree_model_get_font_description (priv->model, &iter);
+  gtk_tree_model_get (priv->filter_model, &iter,
+                      FONT_DESC_COLUMN, &desc,
+                      -1);
 
-  gtk_font_chooser_widget_merge_font_desc (fontchooser, desc, &iter);
+  gtk_font_chooser_widget_merge_font_desc (fontchooser,
+                                           gtk_delayed_font_description_get (desc),
+                                           &iter);
+
+  gtk_delayed_font_description_unref (desc);
 }
 
 static gboolean
@@ -515,6 +552,8 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
+  g_type_ensure (GTK_TYPE_DELAYED_FONT_DESCRIPTION);
+
   widget_class->screen_changed = gtk_font_chooser_widget_screen_changed;
   widget_class->style_updated = gtk_font_chooser_widget_style_updated;
 
@@ -676,23 +715,23 @@ gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser,
 
       for (j = 0; j < n_faces; j++)
         {
-          PangoFontDescription *empty_font_desc;
+          GtkDelayedFontDescription *desc;
           const gchar *face_name;
 
           face_name = pango_font_face_get_face_name (faces[j]);
 
           family_and_face = g_strconcat (fam_name, " ", face_name, NULL);
-          empty_font_desc = pango_font_description_new ();
+          desc = gtk_delayed_font_description_new (faces[j]);
 
           gtk_list_store_insert_with_values (list_store, &iter, -1,
                                              FAMILY_COLUMN, families[i],
                                              FACE_COLUMN, faces[j],
-                                             FONT_DESC_COLUMN, empty_font_desc,
+                                             FONT_DESC_COLUMN, desc,
                                              PREVIEW_TITLE_COLUMN, family_and_face,
                                              -1);
 
           g_free (family_and_face);
-          pango_font_description_free (empty_font_desc);
+          gtk_delayed_font_description_unref (desc);
         }
 
       g_free (faces);
@@ -830,22 +869,21 @@ gtk_font_chooser_widget_cell_data_func (GtkTreeViewColumn *column,
                                         gpointer           user_data)
 {
   GtkFontChooserWidget *fontchooser = user_data;
-  PangoFontDescription *font_desc;
+  GtkDelayedFontDescription *desc;
   PangoAttrList *attrs;
   char *preview_title, *text;
   gsize first_line_len;
 
-  font_desc = tree_model_get_font_description (tree_model, iter);
-
   gtk_tree_model_get (tree_model, iter,
                       PREVIEW_TITLE_COLUMN, &preview_title,
+                      FONT_DESC_COLUMN, &desc,
                       -1);
 
   text = g_strconcat (preview_title, "\n", fontchooser->priv->preview_text, NULL);
   first_line_len = strlen (preview_title) + 1;
 
   attrs = gtk_font_chooser_widget_get_preview_attributes (fontchooser, 
-                                                          font_desc,
+                                                          gtk_delayed_font_description_get (desc),
                                                           first_line_len);
 
   g_object_set (cell,
@@ -853,7 +891,7 @@ gtk_font_chooser_widget_cell_data_func (GtkTreeViewColumn *column,
                 "text", text,
                 NULL);
 
-  pango_font_description_free (font_desc);
+  gtk_delayed_font_description_unref (desc);
   pango_attr_list_unref (attrs);
   g_free (text);
   g_free (preview_title);
@@ -928,26 +966,37 @@ gtk_font_chooser_widget_find_font (GtkFontChooserWidget        *fontchooser,
        valid;
        valid = gtk_tree_model_iter_next (priv->model, iter))
     {
-      PangoFontDescription *desc;
+      GtkDelayedFontDescription *desc;
+      PangoFontDescription *merged;
       PangoFontFamily *family;
 
       gtk_tree_model_get (priv->model, iter,
                           FAMILY_COLUMN, &family,
+                          FONT_DESC_COLUMN, &desc,
                           -1);
 
       if (!my_pango_font_family_equal (pango_font_description_get_family (font_desc),
                                        pango_font_family_get_name (family)))
-        continue;
+        {
+          gtk_delayed_font_description_unref (desc);
+          g_object_unref (family);
+          continue;
+        }
 
-      desc = tree_model_get_font_description (priv->model, iter);
+      merged = pango_font_description_copy_static (gtk_delayed_font_description_get (desc));
 
-      pango_font_description_merge_static (desc, font_desc, FALSE);
-      if (pango_font_description_equal (desc, font_desc)) {
-        pango_font_description_free (desc);
-        break;
-      }
+      pango_font_description_merge_static (merged, font_desc, FALSE);
+      if (pango_font_description_equal (merged, font_desc))
+        {
+          gtk_delayed_font_description_unref (desc);
+          pango_font_description_free (merged);
+          g_object_unref (family);
+          break;
+        }
 
-      pango_font_description_free (desc);
+      gtk_delayed_font_description_unref (desc);
+      pango_font_description_free (merged);
+      g_object_unref (family);
     }
   
   return valid;
@@ -1092,9 +1141,9 @@ gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser)
 }
 
 static void
-gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
-                                         PangoFontDescription *font_desc,
-                                         GtkTreeIter          *iter)
+gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget       *fontchooser,
+                                         const PangoFontDescription *font_desc,
+                                         GtkTreeIter                *iter)
 {
   GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
   PangoFontMask mask;
@@ -1107,10 +1156,7 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
   /* sucky test, because we can't restrict the comparison to 
    * only the parts that actually do get merged */
   if (pango_font_description_equal (font_desc, priv->font_desc))
-    {
-      pango_font_description_free (font_desc);
-      return;
-    }
+    return;
 
   pango_font_description_merge (priv->font_desc, font_desc, TRUE);
   
@@ -1140,8 +1186,6 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
 
   gtk_font_chooser_widget_update_preview_attributes (fontchooser);
 
-  pango_font_description_free (font_desc); /* adopted */
-
   g_object_notify (G_OBJECT (fontchooser), "font");
   g_object_notify (G_OBJECT (fontchooser), "font-desc");
 }
@@ -1171,6 +1215,8 @@ gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
     {
       gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &priv->font_iter);
     }
+
+  pango_font_description_free (font_desc);
 }
 
 static const gchar*
index 429dd2b648959a05af3a413ace34fed782598456..98b6b0edb1a6e4b3ecef28f6bfe137a3a6640ede 100644 (file)
@@ -8,7 +8,7 @@
       <!-- column-name face -->
       <column type="PangoFontFace"/>
       <!-- column-name description -->
-      <column type="PangoFontDescription"/>
+      <column type="GtkDelayedFontDescription"/>
       <!-- column-name preview-title -->
       <column type="gchararray"/>
     </columns>